package org.mte.swift.builder.handler;

import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_COLUMN;
import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_INSERT;
import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_LIST;
import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_SEARCH;
import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_SINGLE;
import static org.mte.swift.builder.model.app.component.PropertyEnm.PT_UPDATE;
import static org.mte.swift.builder.model.placeholder.Placeholder.EDIT_FIELDS_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.ENTITY_CAPITALIZE_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.ENTITY_LOWER_CASE_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.ENTITY_UPPER_CASE_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.GRID_COLMODEL_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.GRID_COLNAMES_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.PACKAGE_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.PRIMARY_KEY_GETTER_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.PRIMARY_KEY_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.PRIMARY_KEY_SETTER_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.PROPERTY_LABELS_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.SHOW_FIELDS_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.TAG_LABELS_PH;
import static org.mte.swift.builder.model.placeholder.Placeholder.VIEW_DIR_PH;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Iterator;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.mte.swift.builder.model.SwiftModel;
import org.mte.swift.builder.model.app.AppModel;
import org.mte.swift.builder.model.app.component.PrimaryKeyReference;
import org.mte.swift.builder.model.app.component.PropertyTag;
import org.mte.swift.builder.model.jpa.ColumnEntity;
import org.mte.swift.builder.model.jpa.Entity;


public class ModelHandlerImpl implements ModelHandler {

		
	public ModelHandlerImpl() {
		
	}
	
	public void fillEntity(SwiftModel swiftModel) throws Exception {
		if (swiftModel.getAppModels() != null) {
			for (AppModel webModel : swiftModel.getAppModels()) {
				Entity entity = webModel.getEntity();
				Class<?> clazz = Class.forName(entity.getClassName());
				Annotation[] ans = clazz.getAnnotations();
				if (ans != null) {
					for (Annotation a : ans) {
						if (a instanceof Table) {
							Table t = (Table) a;
							entity.setTableName(t.name());
						}
					}
				}
				retrieveColumnEntities(clazz.getDeclaredFields(), entity);
			}
		}
	}

	
	private void retrieveColumnEntities(Field[] fields, Entity entity) {
		if (fields != null) {
			for (Field f : fields) {
				boolean isAdd = false;
				String fieldName = f.getName();
				String columnName = null;
				boolean isPrimaryKey = false;				
				Annotation[] ans = f.getAnnotations();
				if (ans != null) {
					for (Annotation a : ans) {
						if (a instanceof Column) {
							Column c = (Column) a;
							isAdd = true;
							columnName = c.name();
						}
						if (a instanceof Id) {
							isPrimaryKey = true;
						}
					}
				}
				if (isAdd) {
					ColumnEntity te = new ColumnEntity(fieldName, columnName, isPrimaryKey);
					entity.getColumnList().add(te);
				}
			}
		}
				
	}
	
	public void initStructures(SwiftModel swiftModel) throws Exception {
		if (swiftModel.getAppModels() != null) {
			for (AppModel appModel : swiftModel.getAppModels()) {					
				createPropertyTags(appModel);
				createPrimaryKeyReference(appModel);
			}
		}
		
	}
	
	
	public void fillPlaceholders(SwiftModel swiftModel) throws Exception {
		if (swiftModel.getAppModels() != null) {
			for (AppModel appModel : swiftModel.getAppModels()) {
				appModel.putPlaceholder(ENTITY_CAPITALIZE_PH, appModel.getEntity().getName());
				appModel.putPlaceholder(ENTITY_LOWER_CASE_PH, appModel.getEntity().getLowName());
				appModel.putPlaceholder(ENTITY_UPPER_CASE_PH, appModel.getEntity().getUpName());
				appModel.putPlaceholder(PACKAGE_PH, appModel.getTargetPackage());
				appModel.putPlaceholder(VIEW_DIR_PH, appModel.getWebDir());
				appModel.putPlaceholder(PROPERTY_LABELS_PH, buildPropertiesLabels(appModel));
				appModel.putPlaceholder(TAG_LABELS_PH, buildTagLabels(appModel));
				appModel.putPlaceholder(PRIMARY_KEY_PH, appModel.getPrimaryKeyReference().getName());			
				appModel.putPlaceholder(GRID_COLNAMES_PH, buildGridColNames(appModel));
				appModel.putPlaceholder(GRID_COLMODEL_PH, buildColModel(appModel));				
				appModel.putPlaceholder(EDIT_FIELDS_PH, buildEditFields(appModel));
				appModel.putPlaceholder(SHOW_FIELDS_PH, buildShowFields(appModel));
				appModel.putPlaceholder(PRIMARY_KEY_SETTER_PH, appModel.getPrimaryKeyReference().getSetter());
				appModel.putPlaceholder(PRIMARY_KEY_GETTER_PH, appModel.getPrimaryKeyReference().getGetter());
			}
		}
	}
	

	private void createPropertyTags(AppModel appModel) {
		Entity entity = appModel.getEntity();
		
		PropertyTag pt = new PropertyTag(
				entity.getLowName() + PT_LIST.label, 
				PT_LIST.value + entity.getName(), 
				PT_LIST.var);
		appModel.getPropertyTagList().add(pt);
		
		pt = new PropertyTag(
				entity.getLowName() + PT_SINGLE.label, 
				PT_SINGLE.value + entity.getName(), 
				PT_SINGLE.var);
		appModel.getPropertyTagList().add(pt);
		
		pt = new PropertyTag(
				entity.getLowName() + PT_INSERT.label, 
				PT_INSERT.value + entity.getName(), 
				PT_INSERT.var);
		appModel.getPropertyTagList().add(pt);
		
		pt = new PropertyTag(
				entity.getLowName() + PT_UPDATE.label, 
				PT_UPDATE.value + entity.getName(), 
				PT_UPDATE.var);
		appModel.getPropertyTagList().add(pt);
		
		pt = new PropertyTag(
				entity.getLowName() + PT_SEARCH.label, 
				PT_SEARCH.value + entity.getName(), 
				PT_SEARCH.var);
		appModel.getPropertyTagList().add(pt);

		
		for (ColumnEntity ce : entity.getColumnList().getEntities()) {
			String fieldName = ce.getFieldName();
			String fc = fieldName.substring(0, 1).toUpperCase();
			String ls = fieldName.substring(1);
			fieldName = fc + ls;
			PropertyTag ptc = new PropertyTag(
					entity.getLowName() + "." + ce.getFieldName() + PT_COLUMN.label, 
					fieldName, 
					ce.getFieldName() + PT_COLUMN.var);
			appModel.getPropertyTagList().add(ptc);
		}
	}
	
	private void createPrimaryKeyReference(AppModel appModel) {
		Iterator<ColumnEntity> iterator = appModel.getEntity().getColumnList().getEntities().iterator();
		String primaryKey = null;
		while (iterator.hasNext() && primaryKey == null) {
			ColumnEntity ce = iterator.next();
			primaryKey = (ce.isPrimaryKey()) ? ce.getFieldName() : null;
		}
		String firstChar = primaryKey.substring(0, 1).toUpperCase();
		String body = primaryKey.substring(1);
		String getter = "get" + firstChar + body;
		String setter = "set" + firstChar + body;
		appModel.setPrimaryKeyReference(new PrimaryKeyReference(primaryKey, getter, setter));
	}
	
	private String buildGridColNames(AppModel appModel) {
		StringBuilder b = new StringBuilder();
		b.append("colNames:[");
		b.append("'Actions', ");
		int size = appModel.getEntity().getColumnList().getEntities().size();
		size = (size > 4) ? 4 : size;
		for (int i = 0; i < size; i++) {
			ColumnEntity ce = appModel.getEntity().getColumnList().get(i);
			b.append("'\\${").append(ce.getFieldName()).append("Label}',");
		}
		b.append("]");
		//gridColNames = "colNames:['Actions', '${id}', '${name}', '${code}']";
		return b.toString();
	}

	private String buildColModel(AppModel appModel) {
		StringBuilder b = new StringBuilder();
		b.append("colModel : [");
		b.append("{name:'act', index:'act', width:10, sortable:false},\n");
		int size = appModel.getEntity().getColumnList().getEntities().size();
		size = (size > 4) ? 4 : size;
		for (int i = 0; i < size; i++) {
			ColumnEntity ce = appModel.getEntity().getColumnList().get(i);
			b.append("{name:'").append(ce.getFieldName()).append("', ");
			b.append("index:'").append(ce.getFieldName()).append("', ");
			b.append("width:").append("15").append("},\n");
		}
		b.append("]");
		return b.toString();
	}
	

	private String buildPropertiesLabels(AppModel webModel) {
		StringBuilder b = new StringBuilder();
		for (PropertyTag pt : webModel.getPropertyTagList().getEntities()) {
			b.append(pt.getCode()).append("=").append(pt.getValue()).append("\n");
		}
		return b.toString();
	}
	
	private String buildTagLabels(AppModel appModel) {
		StringBuilder b = new StringBuilder();
		for (PropertyTag pt : appModel.getPropertyTagList().getEntities()) {
			b.append("\t<spring:message code=\"").append(pt.getCode());
			b.append("\" var=\"").append(pt.getVar()).append("\"/>").append("\n");
		}
		return b.toString();
	}
	
	private String buildEditFields(AppModel appModel) {
		StringBuilder b = new StringBuilder();
		b.append("<div class=\"panel1\">\n");
		for (ColumnEntity ce : appModel.getEntity().getColumnList().getEntities()) {
			b.append("\t\t\t<div class=\"field\">\n");
			b.append("\t\t\t\t<div class=\"field-label\">\n");
			b.append("\t\t\t\t\t<form:label path=\"").append(ce.getFieldName()).append("\">");
			b.append("\\${").append(ce.getFieldName()).append(PT_COLUMN.var).append("}");
			b.append("</form:label>\n");
			b.append("\t\t\t\t</div>\n");
			b.append("\t\t\t\t<div class=\"field-subject\">\n");
			b.append("\t\t\t\t\t<form:input path=\"").append(ce.getFieldName()).append("\"/>\n");
			b.append("\t\t\t\t</div>\n");
			b.append("\t\t\t\t<div><form:errors path=\"").append(ce.getFieldName()).append("\" cssClass=\"error\" /></div>\n");
			b.append("\t\t\t</div>\n");
		}
		b.append("\t\t</div>\n");
		return b.toString();
	}

	private String buildShowFields(AppModel appModel) {
		StringBuilder b = new StringBuilder();
		b.append("<div class=\"panel1\">\n");
		for (ColumnEntity ce : appModel.getEntity().getColumnList().getEntities()) {
			b.append("\t\t\t<div class=\"field\">\n");
			b.append("\t\t\t\t<div class=\"field-label\">\n");
			b.append("\t\t\t\t\t\\${").append(ce.getFieldName()).append(PT_COLUMN.var).append("}\n");
			b.append("\t\t\t\t</div>\n");
			b.append("\t\t\t\t<div class=\"field-subject\">\n");
			b.append("\t\t\t\t\t\\${").append(appModel.getEntity().getLowName()).append(".").append(ce.getFieldName()).append("}\n");
			b.append("\t\t\t\t</div>\n");
			//b.append("\t\t\t\t<div><form:errors path=\"").append(ce.getFieldName()).append("\" cssClass=\"error\" /></div>\n");
			b.append("\t\t\t</div>\n");
		}
		b.append("\t\t</div>\n");		
		return b.toString();
	}
}
